package com.atguigu.gmall.gateway.filter;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

/**
 * @author: 李旭
 * @create: 2021-07-19 15:32
 * <p>
 * 自定义 全局拦截器
 * <p>
 * 网关：默认自带9大过滤器  +  自定义 全局过滤器   == 10大过滤器
 * <p>
 * //第一到第四  第五到第十    路由转发功能的过滤器
 **/
@Component
public class LoginGlobalFilter implements GlobalFilter, Ordered {


    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    public static final String TOKEN = "token";

    @Value("${all.url}")
    private String[] allUrl;


    //拦截器的执行方法
    //新的请求对象  新的响应对象   H是不一样的
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //微服务 ： Tomcat HttpServletRequest HttpServletResponse  同学之前学习过的请求响应
        //网关：   webFlux   ServerHttpRequest  ServerHttpResponse  新的请求响应
        // 使用的服务器技术不一样
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        //MultiValueMap<String, HttpCookie> cookies = request.getCookies();
        //request.getPath()
        //http://list.gmall.com/list?keyword=%E6%89%8B%E6%9C%BA&trademark=1:%E8%8B%B9%E6%9E%9C&props=1:4500-11999:%E4%BB%B7%E6%A0%BC&order=
        String path = request.getURI().getPath();//  /list
        System.out.println(path);
        //MultiValueMap<String, String> queryParams = request.getQueryParams();
        System.out.println(request.getURI().getRawSchemeSpecificPart());
        System.out.println(request.getURI().getScheme());//http
        //    /list
//list.gmall.com/list?keyword=%E6%89%8B%E6%9C%BA&trademark=1:%E8%8B%B9%E6%9E%9C&props=1:4500-11999:%E4%BB%B7%E6%A0%BC&order=
        //http
/////////////////////////////////////////////////////////////////////////////////////////////////////
        //1:inner  内部资源 内部接口 ：允许内部各大微服务调用  不允许网关路由
        //参数1： 路径的规则
        //参数2：路径
        if (antPathMatcher.match("/**/inner/**", path)) {
            //是内部资源 拒绝访问  （跳转页面告知用户 还是Json字串行告知
            return out(response, ResultCodeEnum.PERMISSION);//Mono<Void>
        }
        //2:统一由网关校验用户是否登录
        String userId = getUserId(request);
        if (antPathMatcher.match("/**/auth/**", path) && StringUtils.isEmpty(userId)) {//所有访问都必须登录  后台管理  前台 部分
            //"/**/auth/**",  必须登录  用户ID不存在
            //3.1:未登录
            //--异步 标识  其它全是未登录  /api/product/inner/haha/    /api/order/auth/submit/
            return out(response, ResultCodeEnum.LOGIN_AUTH);//Mono<Void>

        }

        for (String url : allUrl) {
            if (path.indexOf(url) != -1 && StringUtils.isEmpty(userId)) {
                // //3.2:未登录
                // --同步 跳转到登录页面  pay.html order.html trade.html 。。。。。
                response.setStatusCode(HttpStatus.SEE_OTHER);//状态码 303重定向到 登录
                try {
                    response.getHeaders().add(HttpHeaders.LOCATION,
                            "http://passport.gmall.com/login.html?originUrl="
                                    + URLEncoder.encode(request.getURI().toString(), "UTF-8"));//Http  head  K  V
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                //UriUtils.encode(url,utf-8)
                return response.setComplete();
            }
        }

        //4:传递用户ID    真实用户ID   可能出现没有值的
        if (!StringUtils.isEmpty(userId)) {
            request.mutate().header("userId", userId);
        }
        //5:传递临时用户ID
        String userTempId = getUserTempId(request);
        if (!StringUtils.isEmpty(userTempId)) {
            request.mutate().header("userTempId", userTempId);
        }
        //放行
        return chain.filter(exchange);
    }



    @Autowired
    private RedisTemplate redisTemplate;//自定义


    //异步情况下  统一返回值
    public Mono<Void> out(ServerHttpResponse response, ResultCodeEnum resultCodeEnum) {
        Result<Object> result = Result.build(null, resultCodeEnum);
        String json = JSONObject.toJSONString(result);//"1"
        DataBufferFactory dataBufferFactory = response.bufferFactory();
        DataBuffer dataBuffer = dataBufferFactory.wrap(json.getBytes());
        //编码
        response.getHeaders().add(HttpHeaders.CONTENT_TYPE,
                MediaType.APPLICATION_JSON_UTF8_VALUE);
        return response.writeWith(Mono.just(dataBuffer));//Mono<Void>
    }
    //获取临时用户ID
    private String getUserTempId(ServerHttpRequest request) {
        String userTempId = request.getHeaders().getFirst("userTempId");
        if (StringUtils.isEmpty(userTempId)) {
            //从Cookie中
            HttpCookie httpCookie = request.getCookies().getFirst("userTempId");
            if (null != httpCookie) {
                userTempId = httpCookie.getValue();
            }
        }
        return userTempId;//uuid

    }
    //获取用户ID
    private String getUserId(ServerHttpRequest request) {
        //同步时获取Cookie有令牌   异步请求令牌在请求头中 跨域 传递不了Cookie
        String token = request.getHeaders().getFirst(TOKEN);
        if (StringUtils.isEmpty(token)) {
            //从Cookie中
            HttpCookie httpCookie = request.getCookies().getFirst(TOKEN);
            if (null != httpCookie) {
                token = httpCookie.getValue();
            }
        }
        //token
        if (!StringUtils.isEmpty(token)) {
            //连接Redis缓存获取用户ID
            if (redisTemplate.hasKey(token)) {
                return (String) redisTemplate.opsForValue().get(token);
            }
        }
        //未登录 没有token 自然也没有用户ID
        return null;
    }

    // -整数最大  -1  0  1 正的整数最大
    //优化级从左至右越来越低
    @Override
    public int getOrder() {
        return 0;
    }
}
